package com.lemon.core.web;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import com.lemon.core.enums.ServiceEnum;
import com.lemon.core.utils.ConverterUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.util.Map;

/**
 * @author 李猛
 * @datetime 2024/1/15 12:50
 * @description 请求封装
 */
@Slf4j
public class Request {
    /**
     * get 异步请求，无参
     *
     * @param serviceEnum
     * @param uri
     * @param tClass
     * @return
     */
    public static <T> Mono<T> get(ServiceEnum serviceEnum, String uri, Class<T> tClass) {
        String url = getFullUrl(serviceEnum, uri);
        log.info("异步请求.get.url:{},", url);
        return getWebClient().get().uri(url).retrieve().bodyToMono(tClass);
    }

    /**
     * get 异步请求，有参
     *
     * @param serviceEnum
     * @param uri
     * @param param
     * @param tClass
     * @return
     */
    public static <T> Mono<T> get(ServiceEnum serviceEnum, String uri, Object param, Class<T> tClass) {
        String url = getFullUrl(serviceEnum, uri) + getParam(param);
        log.info("异步请求.get.url:{},", url);
        return getWebClient().get().uri(url).retrieve().bodyToMono(tClass);
    }

    /**
     * get 同步请求，无参
     *
     * @param serviceEnum
     * @param uri
     * @param tClass
     * @return
     */
    public static <T> T get(ServiceEnum serviceEnum, String uri, Class<T> tClass, boolean isAsync) {
        if (isAsync) {
            return get(serviceEnum, uri, tClass).block();
        }
        String url = getFullUrl(serviceEnum, uri);
        log.info("同步请求.get.url:{},", url);
        return getRestTemplate().getForObject(url, tClass);
    }

    /**
     * get 同步请求，有参
     *
     * @param serviceEnum
     * @param uri
     * @param param
     * @param tClass
     * @return
     */
    public static <T> T get(ServiceEnum serviceEnum, String uri, Object param, Class<T> tClass, boolean isAsync) {
        if (isAsync) {
            return get(serviceEnum, uri, param, tClass).block();
        }
        String url = getFullUrl(serviceEnum, uri) + getParam(param);
        log.info("同步请求.get.url:{},", url);
        return getRestTemplate().getForObject(url, tClass);
    }

    /**
     * post 异步请求，无参数
     *
     * @param serviceEnum
     * @param uri
     * @param tClass
     * @return
     */
    public static <T> Mono<T> post(ServiceEnum serviceEnum, String uri, Class<T> tClass) {
        String url = getFullUrl(serviceEnum, uri);
        log.info("异步请求.post.url:{},", url);
        return getWebClient().post().uri(url).retrieve().bodyToMono(tClass);
    }

    /**
     * post 异步请求，有参数
     *
     * @param serviceEnum
     * @param uri
     * @param param
     * @param tClass
     * @return
     */
    public static <T> Mono<T> post(ServiceEnum serviceEnum, String uri, Object param, Class<T> tClass) {
        String url = getFullUrl(serviceEnum, uri);
        log.info("异步请求.post.url:{},", url);
        return getWebClient().post().uri(url).bodyValue(param).retrieve().bodyToMono(tClass);
    }

    /**
     * post 同步请求，无参数
     *
     * @param serviceEnum
     * @param uri
     * @param tClass
     * @return
     */
    public static <T> T post(ServiceEnum serviceEnum, String uri, Class<T> tClass, boolean isAsync) {
        if (isAsync) {
            return post(serviceEnum, uri, tClass).block();
        }
        String url = getFullUrl(serviceEnum, uri);
        log.info("同步请求.post.url:{},", url);
        return getRestTemplate().postForObject(url, null, tClass);
    }

    /**
     * post 同步请求，有参数
     *
     * @param serviceEnum
     * @param uri
     * @param param
     * @param tClass
     * @return
     */
    public static <T> T post(ServiceEnum serviceEnum, String uri, Object param, Class<T> tClass, boolean isAsync) {
        if (isAsync) {
            return post(serviceEnum, uri, param, tClass).block();
        }
        String url = getFullUrl(serviceEnum, uri);
        log.info("同步请求.post.url:{},", url);
        return getRestTemplate().postForObject(url, param, tClass);
    }


    /**
     * put 异步请求，无参数
     *
     * @param serviceEnum
     * @param uri
     * @param tClass
     * @return
     */
    public static <T> Mono<T> put(ServiceEnum serviceEnum, String uri, Class<T> tClass) {
        String url = getFullUrl(serviceEnum, uri);
        log.info("异步请求.put.url:{},", url);
        return getWebClient().put().uri(url).retrieve().bodyToMono(tClass);
    }

    /**
     * put 异步请求，有参数
     *
     * @param serviceEnum
     * @param uri
     * @param param
     * @param tClass
     * @return
     */
    public static <T> Mono<T> put(ServiceEnum serviceEnum, String uri, Object param, Class<T> tClass) {
        String url = getFullUrl(serviceEnum, uri);
        log.info("异步请求.put.url:{},", url);
        return getWebClient().put().uri(url).bodyValue(param).retrieve().bodyToMono(tClass);
    }

    /**
     * put 同步请求，无参数
     *
     * @param serviceEnum
     * @param uri
     * @param tClass
     * @return
     */
    public static <T> T put(ServiceEnum serviceEnum, String uri, Class<T> tClass, boolean isAsync) {
        if (isAsync) {
            return put(serviceEnum, uri, tClass).block();
        }
        String url = getFullUrl(serviceEnum, uri);
        log.info("同步请求.put.url:{},", url);
        return getRestTemplate().exchange(url, HttpMethod.PUT, null, tClass).getBody();
    }

    /**
     * put 同步请求，有参数
     *
     * @param serviceEnum
     * @param uri
     * @param param
     * @param tClass
     * @return
     */
    public static <T> T put(ServiceEnum serviceEnum, String uri, Object param, Class<T> tClass, boolean isAsync) {
        if (isAsync) {
            return put(serviceEnum, uri, param, tClass).block();
        }
        String url = getFullUrl(serviceEnum, uri);
        log.info("同步请求.put.url:{},", url);
        return getRestTemplate().exchange(url, HttpMethod.PUT, getRequestEntity(param), tClass).getBody();
    }


    /**
     * delete 异步请求无参
     *
     * @param serviceEnum
     * @param uri
     * @param tClass
     * @return
     */
    public static <T> Mono<T> delete(ServiceEnum serviceEnum, String uri, Class<T> tClass) {
        String url = getFullUrl(serviceEnum, uri);
        log.info("异步请求.delete.url:{},", url);
        return getWebClient().delete().uri(url).retrieve().bodyToMono(tClass);
    }

    /**
     * delete 异步请求有参
     *
     * @param serviceEnum
     * @param uri
     * @param param
     * @param tClass
     * @return
     */
    public static <T> Mono<T> delete(ServiceEnum serviceEnum, String uri, Object param, Class<T> tClass) {
        String url = getFullUrl(serviceEnum, uri) + getParam(param);
        log.info("异步请求.delete.url:{},", url);
        return getWebClient().delete().uri(url).retrieve().bodyToMono(tClass);
    }

    /**
     * delete 同步请求无参
     *
     * @param serviceEnum
     * @param uri
     * @param tClass
     * @return
     */
    public static <T> T delete(ServiceEnum serviceEnum, String uri, Class<T> tClass, boolean isAsync) {
        if (isAsync) {
            return delete(serviceEnum, uri, tClass).block();
        }
        String url = getFullUrl(serviceEnum, uri);
        log.info("同步请求.delete.url:{},", url);
        return getRestTemplate().exchange(url, HttpMethod.DELETE, null, tClass).getBody();
    }

    /**
     * delete 同步请求有参
     *
     * @param serviceEnum
     * @param uri
     * @param param
     * @param tClass
     * @return
     */
    public static <T> T delete(ServiceEnum serviceEnum, String uri, Object param, Class<T> tClass, boolean isAsync) {
        if (isAsync) {
            return delete(serviceEnum, uri, param, tClass).block();
        }
        String url = getFullUrl(serviceEnum, uri) + getParam(param);
        log.info("同步请求.delete.url:{},", url);
        return getRestTemplate().exchange(url, HttpMethod.DELETE, getRequestEntity(param), tClass).getBody();
    }

    /**
     * 获取 WebClient
     *
     * @return
     */
    private static WebClient getWebClient() {
        return SpringUtil.getBean(WebClient.class);
    }

    /**
     * 获取 RestTemplate
     *
     * @return
     */
    private static RestTemplate getRestTemplate() {
        return SpringUtil.getBean(RestTemplate.class);
    }

    /**
     * 处理 uri地址
     *
     * @param uri
     * @return
     */
    private static String getFullUrl(ServiceEnum serviceEnum, String uri) {
        if (uri.startsWith("/")) {
            uri = uri.substring(1);
        }
        if (uri.endsWith("/")) {
            uri.substring(0, uri.length() - 1);
        }
        return String.format("http://%s/%s", serviceEnum.getName(), uri);
    }

    /**
     * 处理参数
     *
     * @param param
     * @return
     */
    private static String getParam(Object param) {
        if (param == null) {
            return "";
        }
        StringBuffer buffer = new StringBuffer();
        JSONObject jsonObject = ConverterUtil.toBean(param, JSONObject.class);
        for (Map.Entry<String, Object> entry : jsonObject) {
            buffer.append(buffer.length() == 0 ? "?" : "&");
            buffer.append(entry.getKey());
            buffer.append("=");
            buffer.append(entry.getValue().toString());
        }
        return buffer.toString();
    }

    /**
     * 获取请求
     *
     * @param param
     * @return
     */
    private static HttpEntity<Map<String, Object>> getRequestEntity(Object param) {
        if (param == null) {
            return null;
        }
        return new HttpEntity<>(BeanUtil.beanToMap(param));
    }
}
